home *** CD-ROM | disk | FTP | other *** search
- Imports System.Threading
-
- ' a control that uses multithreading
-
- Public Class CountdownLabel
- Inherits System.Windows.Forms.Label
-
- ' a delegate that points to the SetText procedure.
- Delegate Sub SetTextDelegate(ByVal Text As String)
-
- ' an instance of this delegate that points to SetText procedure
- Dim SetTextMarshaller As SetTextDelegate = AddressOf Me.SetText
-
- ' internal counter for numbers of left seconds.
- Dim secondsLeft As Integer
- ' end time
- Dim endTime As Date
- ' the thread object (if nothing, no other thread is running).
- Dim thr As Thread
-
- ' the method that starts the countdown
-
- Sub StartCountdown(ByVal seconds As Integer)
- ' wait until all variables can be accessed safely
- SyncLock Me
- ' save values where the other thread can access them.
- secondsLeft = seconds
- endTime = Now.AddSeconds(seconds)
-
- ' create the new thread and run the procedure on that thread
- ' but only if the thread isn't running already
- If (thr Is Nothing) Then
- thr = New Thread(AddressOf CountProc)
- thr.Start()
- End If
- End SyncLock
-
- ' display the initial value in the label
- SetText(CStr(seconds))
- End Sub
-
- ' this method stops the countdown
-
- Sub StopCountdown()
- SyncLock Me
- ' This will implicitly cause the code in CountProc to exit
- endTime = Now
- End SyncLock
- End Sub
-
- ' This procedure is just a wrapper for a simple property set, and must run
- ' on the control's creation thread. The other thread(s) must call it through
- ' SetTextDelegate
-
- Private Sub SetText(ByVal Text As String)
- Me.Text = Text
- End Sub
-
- ' This procedure runs on another thread.
-
- Private Sub CountProc()
- Do
- ' ensure that this is the only thread that is accessing variables.
- SyncLock Me
- ' get the number of seconds left.
- Dim secs As Integer = CInt(endTime.Subtract(Now).TotalSeconds)
-
- ' if different from current value, update the Text property.
- If secs <> secondsLeft Then
- ' never display negative numbers
- If secs < 0 Then secs = 0
- secondsLeft = secs
-
- ' set the Text property with current number of seconds
- Dim args() As Object = {CStr(secondsLeft)}
- MyBase.Invoke(SetTextMarshaller, args)
-
- ' terminate the thread if countdown is over
- If secondsLeft <= 0 Then
- ' signal that no thread is running, and exit
- thr = Nothing
- Exit Do
- End If
-
- End If
- End SyncLock
-
- ' wait for 100 milliseconds
- Thread.Sleep(100)
- Loop
- End Sub
-
- ' kill the other thread if the control is being destroyed.
-
- Protected Overrides Sub OnHandleDestroyed(ByVal e As System.EventArgs)
- SyncLock Me
- If Not (thr Is Nothing) AndAlso thr.IsAlive Then
- thr.Abort()
- thr.Join()
- End If
- End SyncLock
- MyBase.OnHandleDestroyed(e)
- End Sub
- End Class
-